{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 多进程消息队列（multiprocessing.Queue）示例\n",
    "\n",
    "在 Python 的 `multiprocessing` 模块中，`Queue` 是一种进程安全的队列实现，可用于在多个进程之间传递消息。它常用于生产者-消费者模型，或者需要在进程间传递数据的场景。"
   ],
   "id": "c1117ac1a4b6d2f7"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Queue() 函数\n",
    "\n",
    "**功能：**\n",
    "\n",
    "- 创建一个进程安全的队列对象。\n",
    "- 可使用 `put()` 方法向队列中放入数据，使用 `get()` 方法从队列中取出数据。\n",
    "\n",
    "**示例：**"
   ],
   "id": "6c86427af0556f37"
  },
  {
   "cell_type": "code",
   "metadata": {},
   "source": [
    "from multiprocessing import Queue\n",
    "\n",
    "# 创建一个队列对象\n",
    "q = Queue()\n",
    "print(\"队列创建成功，类型为:\", type(q))\n",
    "\n",
    "# 这个示例仅演示Queue的创建，后续会用到 put() 和 get() 方法。"
   ],
   "id": "94c76469d4e6a88c",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. put() 方法\n",
    "\n",
    "**功能：**\n",
    "\n",
    "- 向队列中放入数据（会进行序列化）。\n",
    "- 如果队列已满（可选地指定 `maxsize`），默认会阻塞，直到队列有空闲位置。\n",
    "\n",
    "**示例：**"
   ],
   "id": "a75192ce940f8a57"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在队列中放入数据\n",
    "q.put(\"Hello\")\n",
    "q.put(123)\n",
    "print(\"已向队列中放入字符串 'Hello' 和数字 123\")"
   ],
   "id": "8c1da3adf5c6b952"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. get() 方法\n",
    "\n",
    "**功能：**\n",
    "\n",
    "- 从队列中取出数据（会进行反序列化）。\n",
    "- 如果队列为空，默认会阻塞，直到队列中有可用数据。\n",
    "\n",
    "**示例：**"
   ],
   "id": "9e7738c8cecdda60"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 从队列中取出数据\n",
    "data1 = q.get()\n",
    "data2 = q.get()\n",
    "print(\"从队列取出的数据分别为:\", data1, \"和\", data2)"
   ],
   "id": "33a6346288b00955"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 以上示例只是在同一个进程中演示了 `Queue` 的基础用法：创建、放入、取出数据。在实际应用中，我们通常在不同进程之间使用 `Queue` 来进行通信。"
   ],
   "id": "3da153d17ec6aa0a"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. 多进程队列通信完整示例\n",
    "\n",
    "下面演示一个生产者-消费者模型的示例：\n",
    "\n",
    "- **生产者进程**：往队列中不断放入数据。\n",
    "- **消费者进程**：从队列中取出数据并处理，直到遇到特殊结束标记后退出。\n",
    "\n",
    "通过这个例子，你可以了解如何在不同的进程之间使用 `Queue` 传递消息。"
   ],
   "id": "af91a18e2943be5d"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from multiprocessing import Process, Queue\n",
    "import time\n",
    "\n",
    "def producer(queue):\n",
    "    \"\"\"生产者进程函数，往队列中放入数据\"\"\"\n",
    "    print(f\"[生产者进程] PID: {os.getpid()} 开始运行...\")\n",
    "    for i in range(5):\n",
    "        data = f\"数据-{i}\"\n",
    "        queue.put(data)\n",
    "        print(f\"[生产者进程] 放入: {data}\")\n",
    "        time.sleep(0.5)  # 模拟生产数据的耗时\n",
    "    \n",
    "    # 放入一个特殊标记，表示结束\n",
    "    queue.put(None)\n",
    "    print(f\"[生产者进程] 结束\")\n",
    "\n",
    "def consumer(queue):\n",
    "    \"\"\"消费者进程函数，从队列中获取数据并处理\"\"\"\n",
    "    print(f\"[消费者进程] PID: {os.getpid()} 开始运行...\")\n",
    "    while True:\n",
    "        data = queue.get()\n",
    "        if data is None:\n",
    "            # 遇到 None 表示生产者已经结束，消费者也停止\n",
    "            print(\"[消费者进程] 收到结束标记，退出\")\n",
    "            break\n",
    "        print(f\"[消费者进程] 取出: {data}\")\n",
    "        time.sleep(1)  # 模拟消费数据的耗时\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    # 在主进程中创建队列\n",
    "    queue = Queue()\n",
    "\n",
    "    # 创建生产者和消费者进程\n",
    "    p_producer = Process(target=producer, args=(queue,))\n",
    "    p_consumer = Process(target=consumer, args=(queue,))\n",
    "\n",
    "    # 启动进程\n",
    "    p_producer.start()\n",
    "    p_consumer.start()\n",
    "\n",
    "    # 等待两个进程结束\n",
    "    p_producer.join()\n",
    "    p_consumer.join()\n",
    "\n",
    "    print(\"[主进程] 所有进程结束\")"
   ],
   "id": "d1cf442cdd9da9c4"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 代码说明\n",
    "\n",
    "1. **创建队列**：\n",
    "   ```python\n",
    "   queue = Queue()\n",
    "   ```\n",
    "   在主进程中创建一个队列对象，供生产者进程和消费者进程共享。\n",
    "\n",
    "2. **生产者进程**（`producer` 函数）：\n",
    "   - 使用 `queue.put(data)` 将数据放入队列。\n",
    "   - 最后放入一个特殊标记 `None` 表示数据生产结束。\n",
    "\n",
    "3. **消费者进程**（`consumer` 函数）：\n",
    "   - 使用 `queue.get()` 从队列中获取数据。\n",
    "   - 如果取到的数据是 `None`，说明生产者结束，消费者也随之结束。\n",
    "\n",
    "4. **进程启动和等待**：\n",
    "   - 在 `if __name__ == '__main__':` 块中，创建 `Process` 对象并调用 `start()` 方法启动。\n",
    "   - 使用 `join()` 等待子进程结束。\n",
    "\n",
    "5. **多进程通信的关键点**：\n",
    "   - `Queue` 在多个进程之间共享，可以安全地进行数据的读写。\n",
    "   - 在 Windows 平台上需要将进程的创建代码放在 `if __name__ == '__main__':` 保护之下。"
   ],
   "id": "44375cf2c9ab2e21"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行上述代码后，你会看到：\n",
    "\n",
    "- 生产者进程依次往队列中放入 `数据-0` 到 `数据-4`，然后放入 `None`。\n",
    "- 消费者进程从队列中取出数据并打印，直到取到 `None` 才结束。\n",
    "- 最后主进程打印 \"所有进程结束\"。\n",
    "\n",
    "这样就实现了一个最简单的生产者-消费者模型示例。"
   ],
   "id": "3c6a42cf52d0479c"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 小结\n",
    "\n",
    "- `multiprocessing.Queue()` 用于创建一个进程安全的队列对象。\n",
    "- `queue.put()` 往队列放入数据，`queue.get()` 从队列取出数据。\n",
    "- 在多进程环境下，可以在一个进程中放入数据，另一个进程中取出数据，实现进程间通信。\n",
    "- 切记在 Windows 环境下使用多进程时，需要将进程的创建代码放在 `if __name__ == '__main__':` 块内，以免出现重复导入导致的错误。"
   ],
   "id": "177e3dee2ec99ee9"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "version": "3.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
